package com.example.demo.drools.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.crypto.digest.DigestUtil;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.KieRepository;
import org.kie.api.builder.Message;
import org.kie.api.io.Resource;
import org.kie.api.io.ResourceType;
import org.kie.api.runtime.KieContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


/**
 * kie工具, 管理 kieContainer
 */
public class KieUtil {

	private final static Logger LOG = LoggerFactory.getLogger(KieUtil.class);

	private final static Map<String, String> RULE_KEY_MAP = new ConcurrentHashMap<String, String>();

	private final static KieServices KIE_SERVICES;

	private static KieContainer kieContainer;

	private final static KieFileSystem KIE_FILE_SYSTEM;

	/**
	 * 规则文件扩展名
	 */
	private final static String EXTENSION = ".drl";
	
	/**
	 * 规则路径
	 */
	private static final String RULES_PATH = "src/main/resources/rules/";

	/**
	 * 规则组前缀
	 */
	private final static String SCHEMA_PREFIX = "schema_";

	static {
		KIE_SERVICES = KieServices.Factory.get();
		KIE_FILE_SYSTEM = KIE_SERVICES.newKieFileSystem();
		KIE_SERVICES.newKieBuilder(KIE_FILE_SYSTEM).buildAll();
		kieContainer = KIE_SERVICES.newKieContainer(KIE_SERVICES.getRepository().getDefaultReleaseId());
	}

	/**
	 * 获取规则容器,当规则不存在或有变更时更新规则
	 * @param schemaCode 模式编码
	 * @param ruleDrl 规则
	 * @return
	 */
	public static KieContainer getSchemaRuleContainer(String schemaCode, String ruleDrl) {
		return getRuleContainer(SCHEMA_PREFIX + schemaCode, ruleDrl);
	}

	
	/**
	 * 获取规则容器
	 * @param key
	 * @param ruleDrl
	 * @return
	 */
	private static KieContainer getRuleContainer(String key, String ruleDrl) {
		String ruleMd5 = DigestUtil.md5Hex(ruleDrl);
		String prevSign = RULE_KEY_MAP.get(key);
		if (!ruleMd5.equals(prevSign)) {
			if (prevSign != null) {
				removeRule(prevSign);
			}
			deployRule(ruleMd5, ruleDrl);
			RULE_KEY_MAP.put(key, ruleMd5);
		}
		return kieContainer;
	}

	/**
	 * 删除规则
	 * @param ruleMd5
	 */
	private static void removeRule(String ruleMd5) {
		KieRepository kr = KIE_SERVICES.getRepository();
		String path = getRulePath(ruleMd5);
		KIE_FILE_SYSTEM.delete(path);
		LOG.info("删除规则:{}", path);
		kieContainer = KIE_SERVICES.newKieContainer(kr.getDefaultReleaseId());
	}

	/**
	 * 发布规则
	 * @param ruleMd5
	 * @param ruleContent
	 * @return
	 */
	private static void deployRule(String ruleMd5, String ruleContent) {
		LOG.debug("deploy rule {}", ruleContent);
		KieRepository kr = KIE_SERVICES.getRepository();

		Resource res = KIE_SERVICES.getResources().newByteArrayResource(ruleContent.getBytes()).setResourceType(ResourceType.DRL);
		String path = getRulePath(ruleMd5);
		KIE_FILE_SYSTEM.write(path, res);
		LOG.info("发布规则:{}", path);
		KieBuilder kieBuilder = KIE_SERVICES.newKieBuilder(KIE_FILE_SYSTEM).buildAll();
		List<Message> errors = kieBuilder.getResults().getMessages(Message.Level.ERROR);
		if(CollUtil.isNotEmpty(errors)) {
			StringBuilder sb = new StringBuilder();
			for(Message message : errors) {
				sb.append("path:"+message.getPath()+", text:"+message.getText()+"||");
			}
			LOG.error(sb.toString());
		}
		kieContainer = KIE_SERVICES.newKieContainer(kr.getDefaultReleaseId());
	}

	
	/**
	 * 获取规则文件路径
	 * @param ruleKey
	 * @return
	 */
	private static String getRulePath(String ruleKey) {
		return RULES_PATH + ruleKey + EXTENSION;
	}

	
}
